import os from "os";

import { DynamicBenchmarker } from "../DynamicBenchmarker";

export namespace DynamicBenchmarkReporter {
  export const markdown = (report: DynamicBenchmarker.IReport): string => {
    const format = (value: number | null) =>
      value === null ? "N/A" : (Math.floor(value * 100) / 100).toLocaleString();
    const head = () =>
      [
        "Type",
        "Count",
        "Success",
        "Mean.",
        "Stdev.",
        "Minimum",
        "Maximum",
      ].join(" | ") +
      "\n" +
      new Array(7).fill("----").join("|");
    const row = (title: string, s: DynamicBenchmarker.IReport.IStatistics) =>
      [
        title,
        s.count.toLocaleString(),
        s.success.toLocaleString(),
        format(s.mean),
        format(s.stdev),
        format(s.minimum),
        format(s.maximum),
      ].join(" | ");
    const line = (
      title: string,
      getter: (m: NodeJS.MemoryUsage) => number,
    ): string =>
      `line "${title}" [${report.memories.map((m) => Math.floor(getter(m.usage) / 1024 ** 2)).join(", ")}]`;

    return [
      `# Benchmark Report`,
      "> Generated by [`@nestia/benchmark`](https://github.com/samchon/nestia)",
      ``,
      `  - Specifications`,
      `    - CPU: ${os.cpus()[0].model}`,
      `    - RAM: ${Math.floor(os.totalmem() / 1024 / 1024 / 1024).toLocaleString()} GB`,
      `    - NodeJS Version: ${process.version}`,
      `    - Backend Server: 1 core / 1 thread`,
      `  - Arguments`,
      `    - Count: ${report.count.toLocaleString()}`,
      `    - Threads: ${report.threads.toLocaleString()}`,
      `    - Simultaneous: ${report.simultaneous.toLocaleString()}`,
      `  - Time`,
      `    - Start: ${report.started_at}`,
      `    - Complete: ${report.completed_at}`,
      `    - Elapsed: ${(new Date(report.completed_at).getTime() - new Date(report.started_at).getTime()).toLocaleString()} ms`,
      ``,
      head(),
      row("Total", report.statistics),
      "",
      "> Unit: milliseconds",
      "",
      "## Memory Consumptions",
      "```mermaid",
      "xychart-beta",
      `  x-axis "Time (second)"`,
      `  y-axis "Memory (MB)"`,
      `  ${line("Resident Set Size", (m) => m.rss)}`,
      `  ${line("Heap Total", (m) => m.heapTotal)}`,
      `  ${line("Heap Used + External", (m) => m.heapUsed + m.external)}`,
      `  ${line("Heap Used Only", (m) => m.heapUsed)}`,
      "```",
      "",
      `> - 🟦 Resident Set Size`,
      `> - 🟢 Heap Total`,
      `> - 🔴 Heap Used + External`,
      `> - 🟡 Heap Used Only`,
      "",
      "## Endpoints",
      head(),
      ...report.endpoints
        .slice()
        .sort((a, b) => (b.mean ?? 0) - (a.mean ?? 0))
        .map((endpoint) =>
          row(`${endpoint.method} ${endpoint.path}`, endpoint),
        ),
      "",
      "> Unit: milliseconds",
      "",
      "## Failures",
      "Method | Path | Count | Failures",
      "-------|------|-------|----------",
      ...report.endpoints
        .filter((e) => e.success !== e.count)
        .slice()
        .sort((a, b) => b.count - a.count)
        .map((e) =>
          [
            e.method,
            e.path,
            e.count.toLocaleString(),
            (e.count - e.success).toLocaleString(),
          ].join(" | "),
        ),
    ].join("\n");
  };
}
